/*
 *  实现一个udp 通讯服务类, 需要接收数据的话只需继承改类即可
 */
#pragma once
#ifndef __ADEALL_UDP_SERVER_HPP__
#define __ADEALL_UDP_SERVER_HPP__

#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00 // windwos版本win10

#ifdef _WIN32

#include <winsock2.h>
#include <Windows.h>
#include <ws2ipdef.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#define in_port_t uint16_t
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#endif

#include <stdio.h>

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include "mutexlock.hpp"
#include "thread/thread_base.h"
#include <iostream>
#include <queue>

typedef void FunCallBackFuntion(std::string ip, int port, std::vector<uint8_t>, void *);

// udp 接收数据
struct UDP_MSG
{
    std::string cli_ip;
    in_port_t cli_port;
    std::vector<uint8_t> buffer;
    int len;
};

class ADEALL_UDP_SERVER
{

private:
    static void *UDPrevthreadfunAll(void *);

    static void *Msgthread(void *); // 消息处理线程
    void processMessages();
    int thread_N = 2; // 默认开启两个线程

    std::queue<UDP_MSG> messages_queue;
    MutexLock msg_lock; // 消息队列锁

    void *_context;
    int port;   // 绑定端口
    int srv_fd; // 接收

    // 两个服务器地址
    // struct sockaddr_in srv_addr;
    // struct sockaddr_in6 srv_addr6;

    MutexLock recvcs, sendcs; // 发送锁

    int recvL = 0;
    int ip_mode = 6;
    std::vector<uint8_t> recv_buff2;
    FunCallBackFuntion *_callback;

protected:
    virtual void CallBackFuntion(std::string ip, int port, std::vector<uint8_t>, void *);

public:
    ADEALL_UDP_SERVER(/* args */);
    ~ADEALL_UDP_SERVER();

    // mode 4 = ipv4 ，6 = ipv6
    size_t buff_size = 400; // 缓冲区大小设置
    // 初始化连接，  默认ipv4 线程数2
    int Init(int cliceport, void *, std::string iface = "", int mode = 4, size_t N = 2, FunCallBackFuntion *fun = nullptr);
    int AddMulticast(std::string ip, std::string iface_ip = "0.0.0.0");

    void MessagSend(const char *ip, int port, const char *data, int L, int fd = -1, int mode = -1);
    void MessagSend(const char *ip, int port, const std::string data, int fd = -1, int mode = -1);

    // static int create_Ipv4_fd(std::string iface = "", int cliceport = -1);
    // static int create_Ipv6_fd(std::string iface = "", int cliceport = -1);
    // static int udpSend(const char *ip, int port, const char *data, int L, int send_fd, int ip_mode);

    static int create_Ip_fd(std::string iface = "", int cliceport = -1);
    static int udpSend2(const char *ip, int port, const char *data, int L, int send_fd);
};

#endif